🎯 Понижение размерности
📅 Январь 2026
🔷 1. Суть
- Цель: уменьшить количество признаков
- Зачем: ускорение обучения, визуализация, борьба с переобучением
- Проблема: проклятие размерности
- Решение: сохранить максимум информации в меньшем числе измерений
🔷 2. Зачем нужно
- Визуализация: сжатие до 2-3D для графиков
- Ускорение: меньше признаков → быстрее обучение
- Борьба с шумом: удаление нерелевантных признаков
- Меньше памяти: хранение данных
- Регуляризация: снижение переобучения
🔷 3. Проклятие размерности
При увеличении числа признаков:
- Данные становятся разреженными
- Расстояния теряют смысл
- Нужно экспоненциально больше данных
- Модели переобучаются
Правило большого пальца: на каждый признак нужно минимум 10 наблюдений
🔷 4. Линейные методы
| Метод | Описание | Использование |
| PCA | Главные компоненты | Общее сжатие |
| LDA | Дискриминантный анализ | С метками классов |
| SVD | Сингулярное разложение | Матричная факторизация |
| ICA | Независимые компоненты | Разделение сигналов |
🔷 5. Нелинейные методы
| Метод | Описание | Когда использовать |
| t-SNE | Стохастическое вложение | Визуализация |
| UMAP | Uniform Manifold | Визуализация + предсказания |
| Kernel PCA | PCA с ядром | Нелинейные паттерны |
| Autoencoders | Нейросети | Сложные данные |
| Isomap | Изометрическое отображение | Многообразия |
🔷 6. PCA - базовый пример
from sklearn.decomposition import PCA
from sklearn.preprocessing import StandardScaler
# Масштабирование обязательно!
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)
# PCA
pca = PCA(n_components=2)
X_reduced = pca.fit_transform(X_scaled)
# Объясненная дисперсия
print(f"Variance: {pca.explained_variance_ratio_}")
print(f"Total: {sum(pca.explained_variance_ratio_):.2%}")
# Визуализация
import matplotlib.pyplot as plt
plt.scatter(X_reduced[:, 0], X_reduced[:, 1], c=y)
plt.xlabel('PC1')
plt.ylabel('PC2')
plt.show()
🔷 7. Выбор числа компонент (PCA)
# Метод 1: По порогу дисперсии
pca = PCA(n_components=0.95) # 95% дисперсии
X_reduced = pca.fit_transform(X_scaled)
print(f"Компонент: {pca.n_components_}")
# Метод 2: Scree plot
pca_full = PCA()
pca_full.fit(X_scaled)
plt.plot(range(1, len(pca_full.explained_variance_ratio_) + 1),
pca_full.explained_variance_ratio_, 'bo-')
plt.xlabel('Компонента')
plt.ylabel('Объясненная дисперсия')
plt.title('Scree Plot')
plt.grid(True)
plt.show()
# Метод 3: Кумулятивная дисперсия
cumsum = np.cumsum(pca_full.explained_variance_ratio_)
n_components = np.argmax(cumsum >= 0.95) + 1
print(f"Для 95%: {n_components} компонент")
🔷 8. t-SNE для визуализации
from sklearn.manifold import TSNE
# t-SNE (только для визуализации!)
tsne = TSNE(
n_components=2,
perplexity=30,
learning_rate=200,
n_iter=1000,
random_state=42
)
X_tsne = tsne.fit_transform(X_scaled)
# Визуализация
plt.figure(figsize=(10, 8))
scatter = plt.scatter(
X_tsne[:, 0],
X_tsne[:, 1],
c=y,
cmap='viridis',
alpha=0.6
)
plt.colorbar(scatter)
plt.title('t-SNE проекция')
plt.show()
⚠️ t-SNE только для визуализации! Нельзя использовать transform() на новых данных
🔷 9. UMAP - современная альтернатива
import umap
# UMAP (быстрее t-SNE + можно transform)
reducer = umap.UMAP(
n_components=2,
n_neighbors=15,
min_dist=0.1,
metric='euclidean',
random_state=42
)
X_umap = reducer.fit_transform(X_scaled)
# Применение к новым данным
X_new_umap = reducer.transform(X_new_scaled)
# Визуализация
plt.scatter(X_umap[:, 0], X_umap[:, 1], c=y)
plt.title('UMAP проекция')
plt.show()
🔷 10. LDA для классификации
from sklearn.discriminant_analysis import LinearDiscriminantAnalysis
# LDA (с учетом меток классов)
lda = LinearDiscriminantAnalysis(n_components=2)
X_lda = lda.fit_transform(X_scaled, y)
# Максимум min(n_classes-1, n_features) компонент
print(f"LDA компонент: {lda.n_components}")
# Можно использовать для классификации
y_pred = lda.predict(X_new_scaled)
# Визуализация
plt.scatter(X_lda[:, 0], X_lda[:, 1], c=y)
plt.title('LDA проекция')
plt.show()
🔷 11. Автоэнкодер (простой)
from tensorflow.keras.models import Model
from tensorflow.keras.layers import Input, Dense
# Архитектура
input_dim = X_train.shape[1]
encoding_dim = 32
input_layer = Input(shape=(input_dim,))
encoded = Dense(encoding_dim, activation='relu')(input_layer)
decoded = Dense(input_dim, activation='sigmoid')(encoded)
autoencoder = Model(input_layer, decoded)
encoder = Model(input_layer, encoded)
# Обучение
autoencoder.compile(optimizer='adam', loss='mse')
autoencoder.fit(
X_train, X_train,
epochs=50,
batch_size=256,
validation_split=0.2
)
# Сжатие
X_encoded = encoder.predict(X_train)
🔷 12. Сравнение методов
| Критерий | PCA | t-SNE | UMAP | LDA |
| Скорость | Быстро | Медленно | Быстро | Быстро |
| Нелинейность | Нет | Да | Да | Нет |
| Transform новых | Да | Нет | Да | Да |
| Нужны метки | Нет | Нет | Нет | Да |
| Большие данные | Да | Нет | Да | Да |
🔷 13. Когда использовать
✅ Используйте понижение размерности когда:
- Слишком много признаков (сотни, тысячи)
- Нужна визуализация данных
- Модель переобучается
- Признаки коррелируют
- Медленное обучение
❌ Не используйте когда:
- Признаков мало (< 50)
- Важна интерпретируемость
- Все признаки важны для задачи
- Данных мало (< 1000 точек)
🔷 14. Выбор метода - схема
if нужна_визуализация:
if данных < 10000:
используй t-SNE
else:
используй UMAP
elif есть_метки_классов:
используй LDA
elif нужна_скорость:
используй PCA
elif нужна_нелинейность:
if можешь обучать нейросети:
используй Autoencoder
else:
используй Kernel PCA или UMAP
else:
начни с PCA
🔷 15. Лучшие практики
- Масштабирование: всегда используйте StandardScaler перед PCA/LDA
- Pipeline: объединяйте в sklearn Pipeline
- Кросс-валидация: проверяйте на валидации
- Объясненная дисперсия: контролируйте потерю информации
- Feature selection первым: сначала удалите явно лишнее
🔷 16. Pipeline с PCA
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.decomposition import PCA
from sklearn.ensemble import RandomForestClassifier
# Полный пайплайн
pipeline = Pipeline([
('scaler', StandardScaler()),
('pca', PCA(n_components=0.95)),
('classifier', RandomForestClassifier())
])
# Обучение
pipeline.fit(X_train, y_train)
# Предсказание (все шаги автоматически)
y_pred = pipeline.predict(X_test)
# Оценка
from sklearn.metrics import accuracy_score
print(f"Accuracy: {accuracy_score(y_test, y_pred):.3f}")
🔷 17. Incremental PCA (большие данные)
from sklearn.decomposition import IncrementalPCA
# Для данных, не помещающихся в память
n_batches = 10
ipca = IncrementalPCA(n_components=50)
for X_batch in np.array_split(X_large, n_batches):
ipca.partial_fit(X_batch)
# Transform
X_reduced = ipca.transform(X_large)
print(f"Variance: {sum(ipca.explained_variance_ratio_):.2%}")
🔷 18. Kernel PCA (нелинейный)
from sklearn.decomposition import KernelPCA
# Различные ядра
kernels = ['linear', 'poly', 'rbf', 'sigmoid']
for kernel in kernels:
kpca = KernelPCA(
n_components=2,
kernel=kernel,
gamma=0.1
)
X_kpca = kpca.fit_transform(X_scaled)
plt.scatter(X_kpca[:, 0], X_kpca[:, 1], c=y)
plt.title(f'Kernel PCA ({kernel})')
plt.show()
🔷 19. Сохранение и загрузка
import joblib
# Сохранение
joblib.dump(pca, 'pca_model.pkl')
joblib.dump(scaler, 'scaler.pkl')
# Загрузка
pca_loaded = joblib.load('pca_model.pkl')
scaler_loaded = joblib.load('scaler.pkl')
# Использование
X_new_scaled = scaler_loaded.transform(X_new)
X_new_reduced = pca_loaded.transform(X_new_scaled)
🔷 20. Частые ошибки
- ❌ Не масштабировать данные перед PCA
- ❌ Использовать t-SNE для обучения модели
- ❌ Применять PCA к категориальным признакам
- ❌ Не проверять объясненную дисперсию
- ❌ Делать PCA до train_test_split (утечка данных!)
- ❌ Использовать слишком мало компонент
🔷 21. Правильный порядок
# ✅ ПРАВИЛЬНО
X_train, X_test, y_train, y_test = train_test_split(...)
# Fit только на train
scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train)
pca = PCA(n_components=50)
X_train_pca = pca.fit_transform(X_train_scaled)
# Transform на test
X_test_scaled = scaler.transform(X_test)
X_test_pca = pca.transform(X_test_scaled)
# ❌ НЕПРАВИЛЬНО - fit на всех данных
# scaler.fit(X) # утечка данных!
# pca.fit(X_scaled)
🔷 22. Метрики качества
# Reconstruction error (PCA)
X_reconstructed = pca.inverse_transform(X_reduced)
mse = np.mean((X_scaled - X_reconstructed) ** 2)
print(f"MSE: {mse:.4f}")
# Trustworthiness (t-SNE, UMAP)
from sklearn.manifold import trustworthiness
trust = trustworthiness(X_scaled, X_tsne, n_neighbors=5)
print(f"Trustworthiness: {trust:.3f}")
# Близко к 1.0 - хорошо
# Silhouette score (кластеризация)
from sklearn.metrics import silhouette_score
score = silhouette_score(X_reduced, y)
print(f"Silhouette: {score:.3f}")